#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <jsoncpp/json/json.h>
#define SEP " "             // 空字符
#define SEP_LEN strlen(SEP) // 分隔符长度——不能使用sizeof会带上'\0'
#define LINE_SEP "\r\n"
#define LINE_SEP_LEN strlen(LINE_SEP)

using namespace std;

// 怎么判断一个正文长度content_len读取完了呢？读取到\r\n就表示长度读取完了，长度没有\r\n
// 怎么判断我们一个完整的正文读取结束了呢，根据\r\n吗？是根据我们前面读取到的长度content_len来决定的！

//"content_len"\r\n"x op y"\r\n
bool recvPackage(int sock, string &inbuffer, string *text)
{
    text->clear();
    // 多线程环境下static有问题，修改
    // static std::string inbuffer; // 定义static静态缓冲区，里面我们多余的报文内容会一直存在，读完之后上层可以继续读，数据还在
    char buffer[1024];
    while (true)
    {
        ssize_t n = recv(sock, buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            inbuffer += buffer; // 追加
            // 分析处理
            auto pos = inbuffer.find(LINE_SEP);
            // pos等于-1，表示我目前接收到的报文一个完整的都没有，继续读！然后追加到inbuffer中，然后我再读取报文
            if (pos == std::string::npos)
                continue;
            string text_len_string = inbuffer.substr(0, pos);
            // text_len_string就是"content_len"字符串
            int text_len = stoi(text_len_string);
            // text_len就是正文长度
            int total_len = text_len_string.size() + 2 * LINE_SEP_LEN + text_len;
            // total_len 就是一个完整的报文长度【长度+正文】
            ////  text_len_string + \r\n + text_len + \r\n  <= inbuffer.size()———— 至少有一个完整的报文！
            cout << "处理前inbuffer:\n"
                 << inbuffer << endl;

            if (inbuffer.size() < total_len) // 小于,缓冲里面一个报文没有！
            {
                cout << "输入数据不满足协议，等待后续内容" << endl;
                continue; // 缓冲区继续读，追加到inbuffer，直到我拿到了一个完整的报文
            }
            // 至少有一个完整的报文！
            *text = inbuffer.substr(0, total_len); // 一定拿到了一个完整报文！不多也不少
            inbuffer.erase(0, total_len);          // 拿到一个报文之后，就将该报文清理出缓冲区
            cout << "处理前inbuffer:\n"
                 << inbuffer << endl;

            break;
        }
        else
            return false;
        // else if(n==0)//写端关闭
        // return false;
        // else
        // return false;
    }
    return true;
}
// bool recvRequestALL(int sock, vector<string> *out)//读取多个报文
// {
//     string line;
//     while(recvRequest(sock,&line))
//     {
//         out->push_back(line);
//     }
// }
enum
{
    OK = 0,
    DIV_ZERO,
    MOD_ZERO,
    OP_ERROR
};

////采用方法3：添加自描述方法，在完整的报文前面加上报文的具体长度
// const std::string &enLength(const std::string &text)///////-----返回局部变量的引用，局部变量出作用域会销毁，有问题
const std::string enLength(const std::string &text) // 拿到序列化的结果之后（正文），在前面加上正文的长度
{
    //"x op y" ->  "content_len"\r\n"x op y"\r\n
    //"exitcode result"  -> "content_len"\r\n"exitcode result"\r\n  发送的时候要转换成为这个样子
    //"content_len"
    std::string send_string = to_string(text.size()); // 直接拿到正文长度，然后转为字符串
    //"content_len"\r\n
    send_string += LINE_SEP;
    //"content_len"\r\n"exitcode result"
    send_string += text;
    //"content_len"\r\n"exitcode result"\r\n
    send_string += LINE_SEP;
    return send_string;
}
bool deLength(std::string &package, string *text) // 将拿到的内容的正文长度和正文进行分离，解包
{
    //"content_len"\r\n"x op y"\r\n -> "x op y"
    //"content_len"\r\n"exitcode result"\r\n -> "exitcode result"
    auto pos = package.find(LINE_SEP);
    if (pos == string::npos)
        return false;
    string text_len_string = package.substr(0, pos);
    int text_len = stoi(text_len_string);
    *text = package.substr(pos + LINE_SEP_LEN, text_len);
    return true;
}

class Request // 请求协议
{
public:
    Request()
        : x(0), y(0), op(0)
    {
    }
    Request(int _x, int _y, int _op)
        : x(_x), y(_y), op(_op)
    {
    }
    // 序列化和反序列化，我们发送端未来也是要接收返回数据的，所以说序列化和反序列化的需要
    bool serialize(std::string *out) // 未来将x,y,z进行序列化，转成一个字节流的“字符串”
    {
#ifdef MYSELF
        // 我们的数据怎么进行序列化，具体格式是怎么样的？方法1：自己写；方法2：用现成的。我们这里用自己写的

        // 序列化 ： 结构化->"x op yyyy"  [序列化为：一个请求就一行]
        *out = "";
        string x_string = to_string(x);
        string y_string = to_string(y);
        // std:string op_string = to_string(op);op是字符不用转
        *out = x_string;
        *out += SEP;
        *out += op;
        *out += SEP;
        *out += y_string;
#else
        Json::Value root;
        root["first"] = x;
        root["second"] = y;
        root["oper"] = op;

        Json::FastWriter writer;
        // Json::StyledWriter writer;
        *out = writer.write(root);
#endif
        return true;
    }
    bool deserialize(const std::string in)
    {
#ifdef MYSELF
        // 我们拿到了序列化结果 ： "x op yyyy"
        // 反序列化 "x op yyyyy"->结构化
        auto left = in.find(SEP);
        auto right = in.rfind(SEP);
        if (left == std::string::npos || right == std::string::npos)
            return false; // 你都不是一个表达式了，不满足协议
        if (left == right)
            return false;
        if (right - (left + SEP_LEN) != 1)
            return false; // 只有一个操作符
        std::string x_string = in.substr(0, left);
        std::string y_string = in.substr(right + SEP_LEN);
        if (x_string.empty())
            return false; // 不能为空，0都可以
        if (y_string.empty())
            return false; // 不能为空，0都可以
        x = std::stoi(x_string);
        y = std::stoi(y_string);

        // op = in.substr(left + SEP_LEN, right - (left + SEP_LEN))[0]; // 中括号0，表示一个字符
        op = in[left + SEP_LEN];
#else
        Json::Value root;
        Json::Reader reader;
        reader.parse(in, root);

        x = root["first"].asInt();
        y = root["second"].asInt();
        op = root["oper"].asInt();
#endif
        return true;
    }

    ~Request() {}

public:
    // x op y ------ 这就是协议——规定了x在前，y在后
    int x;
    int y;
    char op;
};
class Response // 响应协议
{
public:
    Response()
        : exitcode(0), result(0)
    {
    }
    Response(int exitcode_, int result_)
        : exitcode(exitcode_), result(exitcode_)
    {
    }
    bool serialize(std::string *out) // 序列化和反序列化，我们发送端未来也是要接收返回数据的，所以说序列化和反序列化的需要
    {
#ifdef MYSELF
        *out = "";
        std::string ec_string = to_string(exitcode);
        std::string res_string = to_string(result);
        *out = ec_string;
        *out += SEP;
        *out += res_string;
#else
        Json::Value root;
        root["exitcode"] = exitcode;
        root["result"] = result;

        Json::FastWriter writer;
        *out = writer.write(root);
#endif
        return true;
    }
    bool deserialize(const std::string &in)
    {
#ifdef MYSELF
        //"exitcode result"
        auto mid = in.find(SEP);
        if (mid == std::string::npos)
            return false;
        std::string ec_string = in.substr(0, mid);
        std::string res_string = in.substr(mid + SEP_LEN);
        if (ec_string.empty() || res_string.empty())
            return false; // 结果为0都可以，就是不能为空
        exitcode = stoi(ec_string);
        result = stoi(res_string);
#else
        Json::Value root;
        Json::Reader reader;
        reader.parse(in, root);

        exitcode = root["exitcode"].asInt();
        result = root["result"].asInt();
#endif
        return true;
        return true;
    }
    ~Response() {}

public:
    int exitcode; // exitcode协议——规定了0表示计算成功，非0表示计算失败。具体是返回多少表示什么错误，要定好标准
    int result;   // 计算结果
};